Skip to content

Close Language Gaps for Commands + Dialogs/Elicitations#960

Open
MRayermannMSFT wants to merge 17 commits intomainfrom
mrayermannmsft/uiandcommandsgaps
Open

Close Language Gaps for Commands + Dialogs/Elicitations#960
MRayermannMSFT wants to merge 17 commits intomainfrom
mrayermannmsft/uiandcommandsgaps

Conversation

@MRayermannMSFT
Copy link
Copy Markdown
Contributor

@MRayermannMSFT MRayermannMSFT commented Mar 31, 2026

What

Adds Commands and UI Elicitation support to the Python, Go, and .NET SDKs, closing the feature gap with the Node.js reference implementation. Each SDK now supports registering slash commands, handling elicitation requests from the server, and driving interactive form dialogs (confirm, select, input) through a capability-gated UI API — with full documentation, unit tests, and E2E tests matching the Node.js test surface.

Why

These two features were recently shipped in the Node.js SDK only, leaving the other three languages unable to participate in command dispatch or elicitation flows. Any multi-language deployment that relied on commands or form-based user input would have been forced to use the Node.js SDK exclusively. Closing this gap ensures all four SDKs offer the same capabilities, preventing fragmentation and letting teams choose the language that fits their stack.

@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review Complete

I've reviewed this PR for consistency across all four SDK implementations (Node.js, Python, Go, .NET).

🎯 Overall Assessment: Exemplary Consistency

This PR successfully adds Commands and UI Elicitation features to all four SDKs with excellent cross-language consistency while appropriately adapting to each language's idioms.


Commands Feature ✅

All four SDKs provide:

  • Consistent command definition: CommandDefinition with name, description, and handler
  • Consistent context object: CommandContext with session ID, command name, command object, and args
  • Appropriate naming conventions:
    • Node.js: registerCommands() with commands?: CommandDefinition[]
    • Python: _register_commands() with commands: list[CommandDefinition]
    • Go: registerCommands() with Commands []CommandDefinition
    • .NET: RegisterCommands() with Commands: List(CommandDefinition)?

UI Elicitation Feature ✅

All four SDKs provide the same four UI methods:

  1. elicitation() - Generic elicitation with custom schemas
  2. confirm() - Boolean confirmation dialogs
  3. select() - Single-choice selection from options
  4. input() - Text input with validation

Handler registration is consistent:

  • Config parameter: onElicitationRequest / on_elicitation_request / OnElicitationRequest
  • Registration method: registerElicitationHandler() / _register_elicitation_handler() / RegisterElicitationHandler()
  • Capabilities check: All SDKs check capabilities.ui.elicitation before allowing calls

Language-appropriate async patterns:

  • Node.js/Python: async/await
  • Go: context.Context parameter
  • .NET: CancellationToken + Task(T)

Documentation & Tests ✅

Documentation: All four README files include complete sections on Commands and UI Elicitation with code examples
Test Coverage: Shared test snapshots ensure behavioral equivalence across SDKs
E2E Tests: Each language has comprehensive E2E tests for both features


🏆 Conclusion

No consistency issues found. This PR maintains excellent feature parity across all four SDKs and demonstrates the gold standard for cross-language SDK development. All language-specific variations are appropriate adaptations to each ecosystem's conventions.

Great work! 🚀

Generated by SDK Consistency Review Agent for issue #960 ·

- Python: fix ruff formatting, add comments to empty except blocks, remove unused imports
- .NET: simplify boolean expressions, combine nested ifs, narrow generic catch clause
- Go: fix struct field alignment for go fmt compliance
@github-actions
Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review: Commands & UI Elicitation ✅

This PR successfully closes the language gaps for Commands and UI Elicitation features across Python, Go, and .NET SDKs. The implementations maintain excellent consistency with the Node.js SDK reference implementation.

✅ Consistent API Surface

All four SDKs now expose parallel APIs with appropriate language conventions:

Feature Node.js Python Go .NET
Commands config commands: CommandDefinition[] commands: list[CommandDefinition] Commands []CommandDefinition Commands IEnumerable(CommandDefinition)
UI confirm session.ui.confirm() session.ui.confirm() session.UI().Confirm() session.Ui.ConfirmAsync()
UI select session.ui.select() session.ui.select() session.UI().Select() session.Ui.SelectAsync()
UI input session.ui.input() session.ui.input() session.UI().Input() session.Ui.InputAsync()
Capabilities check capabilities.ui?.elicitation capabilities.get("ui", {}).get("elicitation") Capabilities().UI.Elicitation Capabilities.Ui?.Elicitation

The naming differences (camelCase vs PascalCase, Async suffix) correctly follow each language's conventions. ✨

✅ Consistent Behavior

All SDKs implement:

  • ✅ Command registration at create_session/resume_session with handler storage
  • ✅ Event routing for command.execute → handler → RPC response via commands.handlePendingCommand
  • ✅ Capability gating for UI methods (throws if elicitation not supported)
  • ✅ Auto-cancel on handler errors
  • ✅ Comprehensive test coverage (E2E + unit tests)
  • ✅ README documentation with code examples

⚠️ Minor Inconsistency Found

One small gap: Go's CommandDefinition.Description field is required while it's optional in Node.js, Python, and .NET.

I've added an inline comment on go/types.go suggesting making it *string to allow nil values. This ensures developers can define commands without descriptions consistently across all SDKs.


Overall: Excellent work bringing feature parity to all SDKs! 🎉 The implementations are well-structured, thoroughly tested, and maintain the parallel API design that makes the SDK easy to use across languages.

Generated by SDK Consistency Review Agent for issue #960 ·

@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review

I've reviewed this PR for consistency across all four SDK implementations (Node.js, Python, Go, and .NET).

Summary

This PR successfully adds Commands and UI Elicitation features to Go, .NET, and Python SDKs to achieve feature parity with the Node.js SDK. The implementation is excellent — all APIs are semantically consistent while following their respective language conventions.

What This PR Adds

Feature Node.js Python Go .NET
Command Definitions ✅ (baseline) ✅ Added ✅ Added ✅ Added
UI Elicitation Methods ✅ (baseline) ✅ Added ✅ Added ✅ Added
Session Capabilities ✅ (baseline) ✅ Added ✅ Added ✅ Added
Elicitation Handler Callback ✅ (baseline) ✅ Added ✅ Added ✅ Added

API Consistency Verification

Command Definitions

All SDKs now expose CommandDefinition with equivalent fields:

  • Node.js: { name, description?, handler }
  • Python: CommandDefinition(name, handler, description?)
  • Go: CommandDefinition{ Name, Description, Handler }
  • .NET: CommandDefinition { Name, Description?, Handler }

UI Elicitation Methods

All SDKs provide the same four methods with appropriate language naming:

  • Generic: elicitation() / Elicitation() / ElicitationAsync()
  • Confirm: confirm() / Confirm() / ConfirmAsync()
  • Select: select() / Select() / SelectAsync()
  • Input: input() / Input() / InputAsync()

Return types follow language idioms:

  • Node.js/Python/.NET: string | null (nullable)
  • Go: (string, bool, error) (idiomatic tuple return) ✅

Capabilities Access

  • Node.js: session.capabilities.ui?.elicitation
  • Python: session.capabilities["ui"]["elicitation"]
  • Go: session.Capabilities().UI.Elicitation
  • .NET: session.Capabilities.Ui?.Elicitation

Test Coverage

The PR includes comprehensive test coverage:

  • ✅ Go: E2E tests in go/internal/e2e/commands_and_elicitation_test.go
  • ✅ .NET: Unit tests in dotnet/test/{CommandsTests,ElicitationTests}.cs
  • ✅ Python: E2E tests in python/e2e/test_{commands,ui_elicitation}.py
  • ✅ Shared test snapshots in test/snapshots/{commands,elicitation}/

Conclusion

No consistency issues found. This PR maintains excellent cross-SDK consistency while respecting language-specific conventions. All four SDKs now have feature parity for Commands and UI Elicitation. 🎉

Generated by SDK Consistency Review Agent for issue #960 ·

…apabilities.changed reliably in replay proxy
@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review: PR #960

I've completed a comprehensive review of this PR to ensure consistency across all four SDK implementations (Node.js, Python, Go, and .NET).

Summary

Overall Assessment: Excellent consistency 🎉

This PR successfully brings Python, Go, and .NET up to feature parity with the existing Node.js SDK for Commands and UI Elicitation APIs. The implementations are highly consistent across all languages, with appropriate adaptations for language-specific idioms.


Features Added

1. Commands API

All three SDKs now support slash commands with consistent structure:

  • Type Definition: CommandDefinition with Name, Description (optional), and Handler
  • Handler Context: CommandContext with session ID, command text, command name, and arguments
  • Registration: Commands registered via SessionConfig during createSession/resumeSession
  • Event Routing: Automatic dispatch to handlers on command.execute events

2. UI Elicitation API

All three SDKs provide four UI methods:

  • elicitation() — Generic method with full schema control
  • confirm() — Boolean yes/no dialog
  • select() — Selection from a list of options
  • input() — Text input with validation options

All methods:

  • Are gated by capability checks (session.capabilities.ui?.elicitation)
  • Throw/error when capabilities are missing
  • Support accept, decline, and cancel actions

Language-Specific Adaptations (All Appropriate ✅)

The implementations correctly adapt to each language's conventions:

Aspect Node.js Python Go .NET
Naming camelCase snake_case PascalCase (exported) PascalCase
Null/None string | null str | None (string, bool, error) string?
Async async/await async/await context.Context Task(T) + CancellationToken
Error Handling Throws Error Raises RuntimeError Returns error Throws InvalidOperationException

Note on Go's (value, ok, error) pattern: Go's Select and Input methods return (string, bool, error) instead of nullable strings. This is an appropriate Go idiom (similar to map lookups) and is well-documented in the README.


Testing Coverage ✅

Comprehensive test coverage added for all three SDKs:

Python:

  • python/test_commands_and_elicitation.py (unit tests)
  • python/e2e/test_commands.py
  • python/e2e/test_ui_elicitation.py
  • python/e2e/test_ui_elicitation_multi_client.py

Go:

  • go/internal/e2e/commands_and_elicitation_test.go
  • Updated existing unit tests in go/client_test.go and go/session_test.go

.NET:

  • dotnet/test/CommandsTests.cs
  • dotnet/test/ElicitationTests.cs
  • dotnet/test/MultiClientCommandsElicitationTests.cs

Shared test snapshots added for replay proxy:

  • test/snapshots/commands/*.yaml
  • test/snapshots/elicitation/*.yaml

Documentation ✅

All README files updated with:

  • Clear examples of command registration
  • UI elicitation capability checking
  • All four UI methods with code samples
  • Elicitation request handlers (server→client)
  • Proper error handling guidance

Verified Consistency Points ✅

  1. Field Names: Consistent across SDKs (accounting for casing conventions)
  2. Method Signatures: Semantically equivalent with language-appropriate types
  3. Capability Checks: All SDKs check capabilities.ui.elicitation before calling UI methods
  4. Error Messages: Consistent wording across SDKs for capability errors
  5. Command Registration: All SDKs support commands in both create and resume flows
  6. RPC Wire Format: Commands serialized as {name, description} arrays (handlers stay client-side)
  7. Action Values: All use "accept", "decline", "cancel" (enum in .NET/Python, string in Go)

No Issues Found

I found no cross-SDK inconsistencies that need to be addressed. The PR maintains excellent feature parity while respecting language-specific conventions.


Recommendation

✅ Approve from a cross-SDK consistency perspective

This PR exemplifies how to properly implement cross-language SDKs: consistent APIs that feel natural in each language.

Generated by SDK Consistency Review Agent for issue #960 ·

…connect

Python's socket.makefile() holds its own reference to the socket.
Calling socket.close() alone won't release the OS-level resource
until the makefile wrapper is also closed. This meant force_stop()
wasn't actually closing the TCP connection, so the server never
detected the disconnect and never sent capabilities.changed events
to other clients.

Fix: close the file wrapper before the socket in SocketWrapper.terminate().
Unskip test_capabilities_changed_when_elicitation_provider_disconnects.
- Narrow generic catch clauses in .NET command/elicitation handlers
  with 'when (ex is not OperationCanceledException)' filter
- Remove redundant null-conditional (val?.ToString -> val.ToString)
  in SelectAsync and InputAsync switch expressions
- Add explanatory comments to Python empty except blocks
@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review

I've reviewed PR #960 for consistency across all four SDK implementations (Node.js, Python, Go, and .NET). This PR successfully adds Commands and UI Elicitation features to Python, Go, and .NET, bringing them to feature parity with the Node.js SDK.

Summary of Changes

Commands Feature:

  • ✅ All three SDKs (Python, Go, .NET) now support registering slash commands via CommandDefinition with name, description, and handler
  • ✅ Consistent command execution flow: command.execute event → handler dispatch → auto-response to CLI
  • ✅ Commands forwarded on both create_session/CreateSession/CreateSessionAsync and resume_session/ResumeSession/ResumeSessionAsync
  • ✅ Error handling: exceptions/errors in handlers are properly reported back to the CLI

UI Elicitation Feature:

  • ✅ All SDKs support the generic elicitation() method with custom schemas
  • ✅ Convenience methods added: confirm(), select(), input() with appropriate language-specific naming (snake_case in Python, PascalCase in Go/.NET)
  • ✅ Capabilities checking: All SDKs properly check session.capabilities.ui?.elicitation and throw/error if not supported
  • ✅ Multi-client support: All SDKs support OnElicitationRequest/on_elicitation_request handler to act as elicitation providers
  • ✅ Capabilities auto-update via capabilities.changed event handling

API Consistency Across Languages

The implementations properly account for language-specific conventions:

Feature Node.js Python Go .NET
Naming camelCase snake_case PascalCase (public) PascalCase
Commands commands?: CommandDefinition[] commands: list[CommandDefinition] Commands []CommandDefinition Commands CommandDefinition[]
Confirm Promise(boolean) bool (bool, error) Task(bool)
Select Promise(string | null) str | None (string, bool, error) ⚠️ Task(string?)
Input Promise(string | null) str | None (string, bool, error) ⚠️ Task(string?)

⚠️ Minor Inconsistency: Go Return Types

Go's Select() and Input() methods return (string, bool, error) where the second boolean indicates whether a selection was made, while other SDKs use nullable/optional types (string | null, string?, str | None) to represent "no selection".

Assessment: This is an acceptable language idiom difference. Go doesn't have nullable reference types, so using multiple return values (value, wasSelected, error) is idiomatic Go. The semantic meaning is equivalent - callers can check the bool flag the same way they'd check for null in other languages.

Example comparison:

// Node.js / TypeScript
const result = await session.ui.select("Pick one", ["a", "b"]);
if (result !== null) { /* user selected */ }
# Python
result = await session.ui.select("Pick one", ["a", "b"])
if result is not None: # user selected
// Go
result, selected, err := session.UI().Select(ctx, "Pick one", []string{"a", "b"})
if err != nil { return err }
if selected { /* user selected */ }
// .NET
var result = await session.Ui.SelectAsync("Pick one", ["a", "b"], cancellationToken);
if (result != null) { /* user selected */ }

Conclusion

✅ This PR maintains excellent cross-SDK consistency. The Commands and UI Elicitation features are implemented uniformly across all languages, with only idiomatic differences appropriate to each language's conventions. No changes needed - the Go tuple return is the correct design for Go.

Generated by SDK Consistency Review Agent for issue #960 ·

…nect

socket.close() and file wrapper close don't reliably interrupt a
blocking readline() on another thread in Python. socket.shutdown(SHUT_RDWR)
sends TCP FIN to the server immediately (triggering server-side
disconnect detection) and interrupts any pending blocking reads
across threads — matching Node.js socket.destroy() and Go conn.Close()
behavior.
@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review: APPROVED

I've completed a comprehensive cross-language consistency review of PR #960. This PR successfully closes the feature gaps for Commands and UI Elicitation across Python, Go, and .NET SDKs, bringing them to parity with the Node.js SDK.

Summary

Scope: Adds three feature gaps to Python, Go, and .NET:

  1. Commands — slash-command registration and handling (/deploy, etc.)
  2. UI Elicitation (client→server)session.ui.confirm(), select(), input(), elicitation()
  3. onElicitationRequest (server→client) — handler for when server needs user input

Node.js SDK: Not modified (already has these features)

✅ Consistency Findings

1. Commands API — Highly Parallel

All SDKs expose consistent command APIs with language-appropriate naming:

Aspect Python Go .NET Node.js
CommandDefinition @dataclass with name, handler, description struct with Name, Handler, Description class with Name, Handler, Description interface with name, handler, description
CommandContext session_id, command, command_name, args SessionID, Command, CommandName, Args SessionId, Command, CommandName, Args sessionId, command, commandName, args
Handler signature Callable[[CommandContext], Awaitable[None] | None] func(CommandContext) error delegate Task CommandHandler(CommandContext) (context) => Promise(void) | void
Response RPC session.commands.handle_pending_command() session.commands.handlePendingCommand() session.commands.handlePendingCommand() session.commands.handlePendingCommand()

All use the same underlying RPC wire protocol and event routing patterns.

2. UI Elicitation API — Highly Parallel

All SDKs expose identical convenience methods with language-appropriate naming:

Method Python Go .NET Node.js
Access session.ui session.UI() session.Ui session.ui
Confirm async def confirm(message: str) → bool func Confirm(ctx, message string) (bool, error) async Task(bool) ConfirmAsync(string) confirm(message: string) → Promise(boolean)
Select async def select(message, options) func Select(ctx, message, options) async Task(string?) SelectAsync(string, string[]) select(message, options)
Input async def input(message, options?) func Input(ctx, message, *opts) async Task(string?) InputAsync(string, InputOptions?) input(message, options?)
Generic async def elicitation(params) func Elicitation(ctx, params) async Task(ElicitationResult) ElicitationAsync(params) elicitation(params)

Capability checking is consistent:

  • Python: _assert_elicitation()RuntimeError
  • Go: assertElicitation() → returns error
  • .NET: AssertElicitation()InvalidOperationException
  • Node.js: Runtime check of session.capabilities.ui?.elicitation

3. onElicitationRequest Handler — Consistent

All SDKs allow registering a handler via SessionConfig:

  • Python: on_elicitation_request: ElicitationHandler
  • Go: OnElicitationRequest: ElicitationHandler
  • .NET: OnElicitationRequest: ElicitationHandler
  • Node.js: onElicitationRequest: ElicitationHandler

All send requestElicitation: true in create/resume when handler is provided.
All auto-cancel on handler errors to prevent server hangs.

4. Test Coverage — Comprehensive

All three target SDKs have:

  • Unit tests for commands and elicitation
  • E2E tests using shared snapshot files (test/snapshots/commands/, test/snapshots/elicitation/)
  • Multi-client capability change tests
  • Error case tests (missing capability throws)

Shared snapshots ensure identical wire protocol behavior across all languages.

5. Documentation — Complete

All three target SDK READMEs updated with:

  • Commands section with examples
  • UI Elicitation section with capability checks
  • onElicitationRequest section with multi-client behavior notes

Verdict

🎉 No consistency issues found. This PR achieves excellent feature parity across all four SDK implementations. The APIs follow language-specific conventions (snake_case vs PascalCase, async/await patterns) while maintaining semantic consistency.

The team successfully applied the principle: same feature, same behavior, language-appropriate naming.

Generated by SDK Consistency Review Agent for issue #960 ·

@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review: APPROVED

I've completed a thorough cross-language consistency review of PR #960, comparing the Commands and UI Elicitation implementations across all four SDKs (.NET, Go, Python, and the reference Node.js implementation).

🎯 Summary

Excellent work! This PR successfully achieves feature parity across all SDK implementations. The APIs are semantically equivalent, follow language-specific naming conventions appropriately, and maintain consistent behavior patterns.


Commands API — Fully Consistent

All four SDKs provide equivalent Commands functionality:

Aspect Status
Registration pattern ✅ Identical (commands field in SessionConfig/ResumeSessionConfig)
Handler signature ✅ Equivalent (async in .NET/Node.js/Python; error-returning in Go)
Context types ✅ Parallel (CommandContext with sessionId, command, commandName, args)
Error handling ✅ Identical ("Unknown command: {name}" messages)
Naming conventions ✅ Appropriate (PascalCase/.NET/Go, camelCase/Node.js, snake_case/Python)

UI Elicitation API — Fully Consistent

All four SDKs expose the same UI methods:

Method .NET Go Python Node.js
Confirm ConfirmAsync() Confirm() confirm() confirm()
Select SelectAsync() Select() select() select()
Input InputAsync() Input() input() input()
Elicitation ElicitationAsync() Elicitation() elicitation() elicitation()

Capability checking: All SDKs properly gate UI methods with session.capabilities.ui.elicitation checks and throw/return errors when unsupported.


📚 Documentation — Comprehensive & Consistent

All three SDK READMEs (dotnet, go, python) have been updated with:

  • Clear examples for Commands registration
  • Complete UI Elicitation documentation
  • Capability checking guidance
  • Elicitation request handling (server→client)

🧪 Test Coverage — Complete

Test files added/modified:

  • .NET: CommandsTests.cs, ElicitationTests.cs, MultiClientCommandsElicitationTests.cs
  • Go: commands_and_elicitation_test.go
  • Python: test_commands.py, test_ui_elicitation.py, test_ui_elicitation_multi_client.py
  • Shared snapshots: 8 new YAML test scenarios under test/snapshots/

📝 Minor Observations (Not blocking)

  1. Go's return type pattern: Go uses (result, ok bool, error) tuples for Select/Input instead of nullable pointers. This is idiomatic Go, though it differs from other SDKs' null returns. Consider documenting this pattern clearly in the README (which you already do! ✅).

  2. Python capability access: Python uses dict key access (session.capabilities["ui"]["elicitation"]) while other SDKs use typed properties. Consider adding a safety note about using .get() to avoid KeyError (or the current code already handles this properly).


🎉 Conclusion

This PR successfully closes the language gaps and brings feature parity to all four SDK implementations. The implementations are:

  • API-equivalent across languages
  • Idiomatically correct for each language
  • Well-documented in all READMEs
  • Comprehensively tested

No consistency issues found. Great work on maintaining parallel implementations! 🚀

Generated by SDK Consistency Review Agent for issue #960 ·

@MRayermannMSFT MRayermannMSFT marked this pull request as ready for review March 31, 2026 20:04
@MRayermannMSFT MRayermannMSFT requested a review from a team as a code owner March 31, 2026 20:04
Copilot AI review requested due to automatic review settings March 31, 2026 20:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR closes feature parity gaps across the SDKs by adding slash commands and UI elicitation dialogs / elicitation callbacks, including capability reporting and multi-client broadcast behavior (capabilities/commands changed) with corresponding docs and tests.

Changes:

  • Adds command registration + command.execute dispatch/response handling across Python, Go, and .NET.
  • Adds UI elicitation APIs (confirm/select/input/custom schema), onElicitationRequest callback handling, and capabilities plumbing (create/resume response + capabilities.changed).
  • Adds/updates E2E + unit tests and replay snapshots to cover single- and multi-client scenarios.

Reviewed changes

Copilot reviewed 36 out of 36 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/snapshots/multi_client/client_receives_commands_changed_when_another_client_joins_with_commands.yaml New replay snapshot for multi-client commands broadcast scenario
test/snapshots/multi_client/capabilities_changed_fires_when_second_client_joins_with_elicitation_handler.yaml New replay snapshot for multi-client capabilities enablement scenario
test/snapshots/multi_client/capabilities_changed_fires_when_elicitation_provider_disconnects.yaml New replay snapshot for multi-client capabilities disablement scenario
test/snapshots/elicitation/session_without_elicitationhandler_reports_no_capability.yaml New replay snapshot for elicitation capability baseline
test/snapshots/elicitation/session_without_elicitationhandler_creates_successfully.yaml New replay snapshot for session creation without elicitation handler
test/snapshots/elicitation/session_without_elicitation_handler_reports_no_capability.yaml New replay snapshot variant for elicitation capability baseline
test/snapshots/elicitation/session_with_elicitationhandler_reports_elicitation_capability.yaml New replay snapshot for elicitation capability when handler is present
test/snapshots/elicitation/session_with_elicitation_handler_reports_elicitation_capability.yaml New replay snapshot variant for elicitation capability when handler is present
test/snapshots/elicitation/sends_requestelicitation_when_handler_provided.yaml New replay snapshot for requestElicitation flag behavior
test/snapshots/elicitation/elicitation_throws_when_capability_is_missing.yaml New replay snapshot for capability-gated UI API behavior
test/snapshots/elicitation/defaults_capabilities_when_not_provided.yaml New replay snapshot for default capabilities behavior
test/snapshots/commands/session_with_no_commands_creates_successfully.yaml New replay snapshot for session creation with no commands
test/snapshots/commands/forwards_commands_in_session_resume.yaml New replay snapshot for resume payload forwarding commands
test/snapshots/commands/forwards_commands_in_session_create.yaml New replay snapshot for create payload forwarding commands
python/test_commands_and_elicitation.py New Python unit coverage for commands, elicitation APIs/callbacks, and capabilities.changed
python/README.md Documents Python commands + UI elicitation + elicitation request handler semantics
python/e2e/test_ui_elicitation.py Python E2E tests for capability gating + capability reporting with handler
python/e2e/test_ui_elicitation_multi_client.py Python E2E multi-client tests for capabilities.changed enable/disable behavior
python/e2e/test_commands.py Python E2E multi-client test for commands.changed broadcast
python/copilot/session.py Implements Python command routing, UI elicitation API, elicitation callback handling, and capabilities updates
python/copilot/client.py Wires commands + requestElicitation flags into create/resume payloads; stores capabilities from responses; improves TCP socket termination
python/copilot/init.py Exposes newly added Python public types (commands/elicitation/capabilities/UI API)
go/types.go Adds Go commands/elicitation/capabilities types and a new Int() pointer helper
go/session.go Implements Go command routing, UI elicitation API, elicitation callback handling, and capabilities storage
go/session_test.go Adds Go unit tests for command routing + capabilities + elicitation gating/handler storage
go/client.go Serializes commands + requestElicitation and registers handlers; stores capabilities from responses
go/client_test.go Adds Go request/response serialization tests for commands + requestElicitation + capabilities
go/README.md Documents Go commands + UI elicitation + elicitation request handling
go/internal/e2e/commands_and_elicitation_test.go Adds Go E2E coverage for commands + elicitation + multi-client capabilities changes
dotnet/test/MultiClientCommandsElicitationTests.cs Adds .NET E2E multi-client tests for commands.changed and capabilities.changed enable/disable
dotnet/test/ElicitationTests.cs Adds .NET E2E + type-structure tests for elicitation + capabilities gating
dotnet/test/CommandsTests.cs Adds .NET E2E + type-structure tests for commands + config cloning
dotnet/src/Types.cs Adds .NET public types for commands, elicitation, UI API, and capabilities; extends config cloning
dotnet/src/Session.cs Implements .NET command routing, elicitation callback handling, UI API, and capabilities updates
dotnet/src/Client.cs Adds commands + requestElicitation to wire requests; stores capabilities from responses; adds JSON source-gen types
dotnet/README.md Documents .NET commands + UI elicitation + elicitation request handler behavior

Go was only passing RequestedSchema.Properties to the elicitation
handler, dropping the 'type' and 'required' fields. This meant
handlers couldn't reconstruct the full JSON Schema. Now passes a
complete map with type, properties, and required.

Also replaces custom containsString/searchSubstring helpers in Go
tests with strings.Contains, and adds tests in Go and Python that
verify the full schema is passed through to elicitation handlers.
Use direct schema extraction logic test instead of dispatching
through session event machinery, avoiding need for RPC mocks.
Fixes undefined SessionEventData and handleEvent references.
@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review: PASSED

This PR successfully brings Commands and UI Elicitation features to Python, Go, and .NET, achieving feature parity with the existing Node.js SDK implementation.

Consistency Analysis

✅ API Structure: All four SDKs now have identical feature sets:

  • CommandDefinition with name, description, and handler
  • ElicitationRequest/ElicitationResult types for server→client requests
  • SessionUI with elicitation(), confirm(), select(), input() methods
  • Capability checking via session.capabilities.ui.elicitation

✅ Naming Conventions: Proper language idioms are followed:

  • Node.js: onElicitationRequest, createSession (camelCase)
  • Python: on_elicitation_request, create_session (snake_case)
  • Go: OnElicitationRequest, CreateSession (PascalCase for exported)
  • .NET: OnElicitationRequest, CreateSessionAsync (PascalCase)

✅ Behavioral Consistency:

  • Commands work with both create and resume operations across all SDKs
  • Elicitation handlers are optional and registered the same way
  • Error handling patterns are similar (capability checks, handler failures)
  • Test snapshots added for all languages

Verification

I verified consistency by comparing:

  • README documentation sections across all four SDKs
  • Type definitions (CommandDefinition, ElicitationRequest, etc.)
  • Session configuration options
  • UI method signatures
  • Test coverage (unit tests + E2E tests for all languages)

No consistency issues found. This PR successfully closes the language gaps for Commands and UI Elicitation features. 🎉

Generated by SDK Consistency Review Agent for issue #960 ·

…tests

- Command handler error propagation: verifies handler error is returned
- Unknown command: verifies getCommandHandler returns false for unknown
- Elicitation handler error: verifies error propagation from handler
- Elicitation handler success: verifies result with action and content
@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review: Commands + UI Elicitation

I've reviewed this PR for consistency across all four SDK implementations. Overall, this PR does an excellent job closing the language gaps and maintaining API parity! 🎉

Summary of Changes

This PR adds Commands and UI Elicitation features to:

  • Go SDK
  • Python SDK
  • .NET SDK

These features already existed in the Node.js SDK, so this PR brings all SDKs to feature parity.


API Consistency Analysis

✅ Commands API - Excellent Consistency

All SDKs implement the same core API pattern:

  • Command Definition: All have name (required), handler (required), description (optional)
  • Handler Context: All provide SessionId, CommandName, Args (Python additionally includes full command text)
  • Event Handling: All process command.execute events and auto-respond
  • Naming: Follows language conventions (camelCase/snake_case/PascalCase) appropriately

Minor architectural difference (acceptable):

  • Node.js: Imperative registration via session.registerCommands()
  • Go/Python/.NET: Declarative via SessionConfig.Commands array

This is a reasonable design choice—Node.js's approach allows dynamic command registration, while the others use configuration-time registration.

✅ UI Elicitation API - Excellent Consistency

All SDKs expose the same 4 UI methods with equivalent signatures:

  1. elicitation() - Generic dialog with JSON schema
  2. confirm() - Boolean confirmation
  3. select() - Dropdown selection
  4. input() - Text input

Capability checking: All SDKs properly gate UI methods behind capabilities.ui.elicitation checks.

Language idioms respected:

  • .NET: Uses Async suffix + CancellationToken pattern
  • Go: Returns explicit error tuples + selection flags
  • Python: Uses Optional types + async/await
  • Node.js: Promise-based with nullable returns

📚 Documentation Gap Found

Issue: The .NET README is missing a dedicated Commands section with code examples.

Current state:

  • ✅ Go README: Has dedicated "Commands" section + 2 examples
  • ✅ Python README: Has dedicated "Commands" section + 2 examples
  • ✅ Node.js README: Has dedicated "Commands" section + 1 example
  • ❌ .NET README: Commands only mentioned briefly in "Elicitation Requests" section, no code examples

Recommendation: Add a dedicated "Commands" section to dotnet/README.md matching the structure of other SDKs:

### Commands

Register slash commands that users can invoke via `/commandName` in the CLI TUI:

```csharp
var session = await client.CreateSessionAsync(new SessionConfig
{
    Commands = new List(CommandDefinition)
    {
        new()
        {
            Name = "deploy",
            Description = "Deploy the application",
            Handler = async (context, ct) =>
            {
                Console.WriteLine($"Deploying to {context.Args}...");
                // Your deployment logic here
            }
        }
    }
});
```

The handler receives a `CommandContext` with:
- `SessionId`: Current session identifier
- `CommandName`: Command name (without `/`)
- `Args`: Raw argument string

✅ Test Coverage - Complete

All SDKs now have comprehensive test coverage:

  • ✅ Unit tests for Commands
  • ✅ Unit tests for UI Elicitation
  • ✅ E2E tests using shared snapshots (test/snapshots/commands/, test/snapshots/elicitation/)
  • ✅ Multi-client scenarios

Conclusion

This PR successfully achieves cross-SDK consistency! The only improvement needed is enhancing the .NET documentation to match the clarity of other SDKs. The API implementations are solid and maintain appropriate language idioms while ensuring semantic equivalence.

Suggested next step: Add the Commands documentation section to dotnet/README.md before merging.

Generated by SDK Consistency Review Agent for issue #960 ·

…ET README

Matches Go and Python README structure where these are ## (h2) sections
rather than ### (h3) subsections. Closes documentation gap flagged
by SDK Consistency Review Agent.
@github-actions
Copy link
Copy Markdown
Contributor

✅ Cross-SDK Consistency Review: APPROVED

I've completed a thorough review of PR #960 for cross-language SDK consistency. This PR adds Commands and UI Elicitation features to the Go, Python, and .NET SDKs, bringing them to feature parity with the Node.js/TypeScript SDK which already has these capabilities.

Summary of Changes

The PR adds two major features across three SDKs:

1. Commands API (Slash Commands)

  • Allows registration of custom /commandName handlers
  • Consistent structure: CommandDefinition with name, description, and handler
  • Handler receives context with sessionId, command, commandName, and args
  • Commands forwarded in both CreateSession and ResumeSession calls

2. UI Elicitation API (Interactive Dialogs)

  • Capability-gated UI methods: confirm(), select(), input(), and generic elicitation()
  • session.capabilities.ui.elicitation reports support dynamically
  • Consistent error handling: throws/errors when capability not available
  • Elicitation handler registration via OnElicitationRequest callback

✅ Consistency Analysis

API Surface Parity:

  • ✅ All four SDKs now have identical feature sets
  • ✅ Method names follow language conventions (camelCase/snake_case/PascalCase)
  • ✅ Parameter types and return values are semantically equivalent
  • ✅ Handler signatures are parallel across languages:
    • Node.js: CommandHandler = (context: CommandContext) => Promise(void) | void
    • Python: CommandHandler = Callable[[CommandContext], Awaitable[None] | None]
    • Go: CommandHandler func(ctx CommandContext) error
    • .NET: CommandHandler delegate Task(CommandContext context)

Documentation Consistency:

  • ✅ README updates for all three SDKs with parallel examples
  • ✅ Capability checking patterns documented consistently
  • ✅ Error handling guidance matches across languages

Test Coverage:

  • ✅ Shared snapshot tests in test/snapshots/commands/ and test/snapshots/elicitation/
  • ✅ Unit tests added for each SDK (CommandsTests, ElicitationTests)
  • ✅ Multi-client capability change tests ensure dynamic feature negotiation works

Wire Protocol:

  • ✅ RPC payload structures are identical (commands, requestElicitation flags)
  • ✅ Capabilities response handling consistent (session.capabilities.ui.elicitation)
  • ✅ Event routing (command.execute, elicitation.requested) implemented uniformly

🎯 Key Observations

  1. Language Idioms Respected: The PR correctly adapts API patterns to each language's conventions (e.g., Go returns (result, error) tuples, while Python/Node.js use exceptions/promise rejections).

  2. Backwards Compatible: Changes are purely additive - no breaking changes to existing APIs.

  3. Comprehensive: Both the happy path and error scenarios are covered with proper tests.

  4. Documentation Quality: READMEs include clear capability checks and usage examples for all new features.

🏁 Conclusion

This PR successfully closes the feature gap between SDKs. All four language implementations now have:

  • ✅ Commands registration and execution
  • ✅ UI elicitation with capability gating
  • ✅ Consistent error handling
  • ✅ Parallel documentation

No consistency issues found. The implementation maintains excellent cross-SDK parity while respecting each language's idiomatic patterns.

Generated by SDK Consistency Review Agent for issue #960 ·

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants